/* ------------------------------------------------------------------------*
 *
 * ------------------------------------------------------------------------*/
#include "bsp.h"
#include "stdint.h"
#include "os_obj.h"
#include "nor_cmd.h"
#include "bsp_spi_nor.h"
#include "log_buff_manage.h"
#include "extblockflashlog.h"
#include "str_ext.h"
#include "common.h"
/*****************************************************************************
 * @brief   delay .
 *****************************************************************************/

static void LogErase(uint32_t AddrBase);							/*从指定地址擦除，Nums指定擦除的扇区个数*/
static void LogProgram(uint32_t Addr, uint8_t *Data, uint16_t Len); /*向指定指定地址编程数据*/
static void LogRead(uint32_t Addr, uint8_t *Data, uint16_t Len);	/*读取块数据*/
static void LogFlashFullCallBack(uint8_t mode);						/*存满回调*/

int32_t log_blk_iter_back(int32_t site, uint8_t *dat);
void block_log_read(const block_log_cfg_type *cfg, int32_t site, uu8 *dat);
static char power_off_sim = 0;

// 日志数据
typedef struct
{
	sig_time_type time;
	uint16_t temp_pv;
	uint16_t temp_sv;
	uint16_t humi_pv;
	uint16_t humi_sv;
	uint16_t ver[200];
} log_dat_type;

static log_dat_type log_dat;

////////////////////////////////////////////////////////////////////////////////
// 日志缓存配置
log_buff_api_ref(log_buff_cfg);
log_buff_info_type log_buff_info;
log_buff_cfg_type log_buff_cfg = {
	.buff_amount = 4,
	.first_base = (768) * 1024,
	.buff_size = 32 * 1024,
	.page_size = 4 * 1024,
	.log_size = 200,
	.info = &log_buff_info,
	.erase = LogErase,
	.program = LogProgram,
	.read = LogRead,
	.full_callback = LogFlashFullCallBack,
	.api = log_buff_api_name(log_buff_cfg)};
log_buff_api_make(log_buff_cfg);

////////////////////////////////////////////////////////////////////////////////
static void BlkProgram(uint32_t Addr);
static void BlkRead(uint32_t Addr, uint16_t Len, uint8_t *Data);
static void BlkErase(uint32_t AddrBase);
block_log_api_ref(blk_log_cfg);
block_log_info_type blk_log_info;
const block_log_cfg_type blk_log_cfg = {
	.block_amount = 4,
	.block_base = 28,
	.Info = &blk_log_info,
	.buf = &log_buff_cfg,
	.Erase = BlkErase,
	.Program = BlkProgram,
	.Read = BlkRead,
	.api = block_log_api_name(blk_log_cfg)};
block_log_api_make(blk_log_cfg);

void blk_init_auto(void)
{
	log_buff_cfg.api->init();
	blk_log_cfg.api->init();
}
obj_init_order5(blk_init_auto);

/*******************************************************************************
 * @brief: 初始化
 * @param cfg
 * @return {*}
 ******************************************************************************/
int blk_log_init(int argc, char **argv)
{
	log_buff_cfg.api->init();
	blk_log_cfg.api->init();

	dbg_print("log buf info: base %dKB, next: %d, page sit: %d, total: %d" PTCR,
			  log_buff_cfg.info->flash_base >> 10,
			  log_buff_cfg.info->site_next,
			  log_buff_cfg.info->sits_per_page,
			  log_buff_cfg.info->sits_total);

	dbg_print("blk info: start %d, next %d \n", blk_log_cfg.Info->block_start, blk_log_cfg.Info->block_next);

	return 0;
}
DBG_FUN_EXPORT(blk_log_init);

/*******************************************************************************
 * @brief: 清除
 * @param cfg
 * @return {*}
 ******************************************************************************/
int blk_log_clr(int argc, char **argv)
{
	loop(log_buff_cfg.buff_size / log_buff_cfg.page_size * log_buff_cfg.buff_amount)
	{
		LogErase(log_buff_cfg.first_base + index * log_buff_cfg.page_size);
	}

	loop(blk_log_cfg.block_amount)
	{
		BlkErase(blk_log_cfg.block_base + index);
	}

	log_buff_cfg.api->init();
	blk_log_cfg.api->init();

	log_dat.humi_pv = 0;
	log_dat.time.val = 0;

	dbg_puts("clear end" PTCR);
	dbg_puts(SYMBOL_LINE_EQ PTCR);

	return 0;
}
DBG_FUN_EXPORT(blk_log_clr);

/*******************************************************************************
 * @brief: 存储
 * @param cfg
 * @return {*}
 ******************************************************************************/
int blk_log_save(int argc, char **argv)
{
	int cnt = 1, tim = log_dat.time.val;

	if (argc > 1)
		cnt = atoi(argv[1]);

	if (argc > 2)
		tim = atoi(argv[2]);

	// 保存日志
	while (cnt--)
	{
		log_dat.time.val = tim;
		log_dat.temp_pv = (log_dat.temp_pv + 3) & 0x7FF;
		log_buff_cfg.api->save(&log_dat);
		log_dat.humi_pv++;
		tim += 5;
	}

	dbg_puts("save end" PTCR);
	dbg_puts(SYMBOL_LINE_EQ PTCR);

	return 0;
}
DBG_FUN_EXPORT(blk_log_save);

/*******************************************************************************
 * @brief: 读取
 * @param cfg
 * @return {*}
 ******************************************************************************/
int blk_log_buf_read(int argc, char **argv)
{
	int sit = 1, num = 1;
	log_dat_type ld;

	if (argc > 1)
		sit = atoi(argv[1]);

	if (argc > 2)
		num = atoi(argv[2]);

	// 保存日志
	while (num--)
	{
		log_buff_cfg.api->read(sit++, &ld);

		dbg_print("site:%6d, tim:%8d, temp:%d, humi:%d" PTCR, sit, ld.time.val, ld.temp_pv, ld.humi_pv);

		if (sit >= log_buff_cfg.info->site_next)
			break;
	}

	dbg_puts(SYMBOL_LINE_EQ PTCR);

	return 0;
}
DBG_FUN_EXPORT(blk_log_buf_read);

/*******************************************************************************
 * @brief: 读取
 * @param cfg
 * @return {*}
 ******************************************************************************/
int blk_log_read(int argc, char **argv)
{
	int sit = 1, num = 1;
	log_dat_type ld;

	if (argc > 1)
		sit = atoi(argv[1]);

	if (argc > 2)
		num = atoi(argv[2]);

	// 保存日志
	while (num--)
	{
		blk_log_cfg.api->read(sit++, (uu8 *)&ld);

		dbg_print("site:%6d, tim:%8d, temp:%d, humi:%d" PTCR, sit, ld.time.val, ld.temp_pv, ld.humi_pv);

		if (sit == block_log_get_next_site(&blk_log_cfg))
			break;

		sit %= blk_log_cfg.Info->log_num_total;
	}

	dbg_puts(SYMBOL_LINE_EQ PTCR);

	return 0;
}
DBG_FUN_EXPORT(blk_log_read);

/*--------------------------------------------------------------------------------*
 * log buff hal
 *--------------------------------------------------------------------------------*/
void LogProgram(uint32_t Addr, uint8_t *Data, uint16_t Len)
{
	nor_write_multi(Addr, Len, (uu8 *)Data);
}

void LogRead(uint32_t Addr, uint8_t *Data, uint16_t Len)
{
	nor_read(Addr, Len, (uu8 *)Data);
}

void LogErase(uint32_t AddrBase)
{
	nor_sector_erase(AddrBase);
}

void LogFlashFullCallBack(uint8_t mode)
{
	dbg_print("log buffer full call back \n");

	block_log_save(&blk_log_cfg);

	dbg_print("blk info: start %d, next %d \n", blk_log_cfg.Info->block_start, blk_log_cfg.Info->block_next);

	if (power_off_sim)
	{
		osDelay(10);
		NVIC_SystemReset();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////
int blk_log_siter(int argc, char **argv)
{
	int s = 1, e = 1;

	if (argc > 1)
		s = atoi(argv[1]);

	if (argc > 2)
		e = atoi(argv[2]);

	// 保存日志
	block_log_site_iter(&blk_log_cfg, s, e, log_blk_iter_back);

	dbg_puts(SYMBOL_LINE_EQ PTCR);

	return 0;
}
DBG_FUN_EXPORT(blk_log_siter);

int blk_log_titer(int argc, char **argv)
{
	int s = 1, e = 1;

	if (argc > 1)
		s = atoi(argv[1]);

	if (argc > 2)
		e = atoi(argv[2]);

	// 保存日志
	block_log_time_iter(&blk_log_cfg, s, e, log_blk_iter_back);

	dbg_puts(SYMBOL_LINE_EQ PTCR);

	return 0;
}
DBG_FUN_EXPORT(blk_log_titer);

int32_t log_blk_iter_back(int32_t site, uint8_t *dat)
{
	log_dat_type *ld;

	ld = (log_dat_type *)dat;

	dbg_print("site:%6d, tim:%8d, temp:%d, humi:%d" PTCR, site, ld->time.val, ld->temp_pv, ld->humi_pv);

	return 1;
}

void BlkProgram(uint32_t blk)
{
	uu8 *buff = malloc(blk_log_cfg.buf->page_size);

	nor_block_erase(blk * 32 * 1024);

	loop(blk_log_cfg.buf->buff_size / blk_log_cfg.buf->page_size)
	{
		nor_read(blk_log_cfg.buf->info->flash_base + index * blk_log_cfg.buf->page_size,
				 blk_log_cfg.buf->page_size,
				 (uu8 *)buff);

		nor_write_multi(blk * 32 * 1024 + index * blk_log_cfg.buf->page_size,
						blk_log_cfg.buf->page_size,
						(uu8 *)buff);
	}

	free(buff);

	dbg_print("block write : %d" PTCR, blk - blk_log_cfg.block_base);
}

void BlkRead(uint32_t Addr, uint16_t Len, uint8_t *Data)
{
	nor_read(Addr, Len, (uu8 *)Data);
}

void BlkErase(uint32_t blk)
{
	nor_block_erase(blk * 32 * 1024);
}

int log_blk_power_sim(int argc, char **argv)
{
	power_off_sim = 1;

	dbg_print("power down sim req, please save data" PTCR);

	return 0;
}
DBG_FUN_EXPORT(log_blk_power_sim);
